/*
Requirements
	1. Accept item scan/UPC
	2. Validate customer age
	3. Remove items from transaction (requires manager/supervisor override, to minimize inventory shrinkage)
	4. Accept payment details
UI Requirements	
	1. Scan an item
	2. Enter an item manually (by UPC)
	3. Validate customer age
	4. Remove items from transaction (requires manager/supervisor override, to minimize inventory shrinkage)
	5. Display sub-total, tax and total price onscreen
	6. Print receipts listing all items, sub-total, tax and total price
	7. Accept payment details
*/

const char* CashierBackend_DBQuery_ItemInfo = "select * from `ItemInfo` where id = {0};";
const char* CashierBackend_DBQuery_RestrictionInfo = "select * from `RestrictionInfo` where type = '{0}';";

#include "CashierBackend.h"
#include <time.h>

CashierBackend::CashierBackend()
{
}

CashierBackend::~CashierBackend()
{
	DBHandler.Release();
}

CashierBackend::Init(Handle<DBInstance> db)
{
	DBHandler = db;
}

NetworkMessage CashierBackend::OnEvent(unsigned long event, NetworkMessage msg)
{
	switch (event)
	{
		case (CashierBackEndEvent_ItemInfo):
			return GetItemInfo(msg);
		case (CashierBackendEvent_ValidateInfo):
			return ValidateInfo(msg);
		case (CashierBackendEvent_ProcessTransactionItems):
			return ProcessTransItems(msg);
		case (CashierBackendEvent_ProcessTransactionPayment):
		case (CashierBackendEvent_ProcessTransactionPayCash):
			return ProcessTransPayCash(msg);
		case (CashierBackendEvent_ProcessTransactionPayCard):
			return ProcessTransPayCard(msg);
		case (CashierBackendEvent_ProcessTransactionPayCheck):
			return ProcessTransPayCheck(msg);
		default:
			break;
	};
	NetworkMessage ret;
	ret.WriteDoubleWord(CashierBackendEvent_Error);
	ret.WriteString("Unknown event");
	return ret;
}

NetworkMessage CashierBackend::GetItemInfo(NetworkMessage& msg)
{
/*
	Pseudo structure: (in)
		Item ID: 32-bit (QuadWord)
	Pseudo structure: (out)
		Valid: 8-bit (0:false, non-0: true)
		Item Name: string
		Item Price: 16-bit (in smallest denomination of currency)
		Tax Rates: 8-bit (percentage)
		Special Flags: 8-bit (alcohol, tobaco, etc)
*/
	unsigned long ID = msg.ReadQuadWord();
	NetworkMessage ret;
	DBQuery query;
	query.SetFormatString(CashierBackend_DBQuery_ItemInfo);
	query.BindData(0, (int)ID);
	IDBQueryResult* res = (*DBHandler)->Query(query);
	if (!res)
	{
		ret.WriteByte(0);
		return ret;
	}
	ret.WriteByte(0xFF);
	std::string name;
	unsigned short price;
	unsigned char tax, flags;
	name = res->GetString("name");
	price = (unsigned short)res->GetDoubleWord("price");
	tax = (unsigned char)res->GetDoubleWord("tax");
	flags = (unsigned char)res->GetDoubleWord("flags");
	ret.WriteString(name);
	ret.WriteWord(price);
	ret.WriteByte(tax);
	ret.WriteByte(flags);
	return ret;
}

NetworkMessage CashierBackend::ValidateInfo(NetworkMesage& msg)
{
/*
	(in)
		Item ID: 32-bit (QuadWord)
		(Restriction Info)
			Birth Year: 16-bit
			Birth Month: 8-bit
			Birth Day: 8-bit
	(out)
		Valid: 8-bit (0: false, 1: true, [2,FF]: invalid item ID or DB error)
*/
	unsigned long ID = msg.ReadQuadWord();
	NetworkMessage ret;
	DBQuery query;
	query.SetFormatString(CashierBackend_DBQuery_ItemInfo);
	query.BindData(0, (int)ID);
	IDBQueryResult* res = (*DBHandler)->Query(query);
	if (!res)
	{
		ret.WriteByte(0xFF);
		return ret;
	}
	std::string type = res->GetString("restriction");
	if (type == "age")
	{
		int age;
		query.Reset();
		query.SetFormatString(CashierBackend_DBQuery_RestrictionInfo);
		query.BindData(0, type);
		delete res;
		res = (*DBHandler)->Query(query);
		if (!res)
		{
			ret.WriteByte(0xFF);
			return ret;
		}
		age = res->GetString("value");
		unsigned int year, month, day;
		year = msg.ReadWord();
		month = msg.ReadByte();
		day = msg.ReadByte();
		if (year > 1900)
		{
			year -= 1900;
		}
		time_t r1, r2, r3;
		tm tm1, tm2;
		r1 = time(NULL); // current day
		tm = *(localtime(r1));
		memset(&tm2, 0, sizeof(tm));
		tm1.tm_sec = tm1.tm_min = tm1.tm_hour = 0;
		r2 = mktime(&tm1);
		tm2.tm_mon = month;
		tm2.tm_mday = day;
		tm2.tm_year = year;
		r3 = mktime(&tm2);
		if (r3 < 0 || r2 < 0)
		{
			ret.WriteByte(0xFF);
		}
		else if (r2 >= r3)
		{
			ret.WriteByte(1);
		}
		else
		{
			ret.WriteByte(0);
		}
	}
	return ret;
}

/*
	NetworkMessage ProcessTransItems(NetworkMessage&);
	NetworkMessage ProcessTransPayCash(NetworkMessage&);
	NetworkMessage ProcessTransPayCard(NetworkMessage&);
	NetworkMessage ProcessTransPayCheck(NetworkMessage&);
*/


